﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections;
using System.Web.UI.WebControls;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.WebControls;
using SPPropertyBagViewer.Helpers;

namespace SPPropertyBagViewer.Layouts.SPPropertyBagViewer
{
    public partial class SPPropertyBagViewer : LayoutsPageBase
    {

        private enum PropertyBagItemType
        {
            Web,
            List,
            Item
        }

        #region const
        private const string ListIdParamName = "ListId";
        private const string ItemIdParamName = "ItemId";
        private const string EnalblePbvForItemsKey = "SPPropertiBagViewer_EnablePbvForListItems";
        private const string EnalblePbvForItemsPermissionsKey = "SPPropertiBagViewer_EnalblePbvForItemsPermissions";
        private const string MenuTitle = "Propery Bag Viwer";
        private const string UrlToViewPage =
            "javascript:window.open('{SiteUrl}/_layouts/SPPropertyBagViewer/SPPropertyBagViewer.aspx?ListId={ListId}&amp;ItemId={ItemId}','_blank');";
        #endregion


        private string _listId, _itemId;
        private PropertyBagItemType _pbItemType;
        public string PageTitleSufix;

        protected void Page_Load(object sender, EventArgs e)
        {
            if (SPContext.Current == null)
            {
                ShowMessage("SPContext is undefined");
                return;
            }

            try
            {
                _listId = GetParamFromUrlByName(ListIdParamName);
                _itemId = GetParamFromUrlByName(ItemIdParamName);
                _pbItemType = GetPbItemType(_listId, _itemId);

                Preparation();

                BindPBInfo();
            }
            catch (Exception ex)
            {
                ShowMessage(ex.ToString());
            }
        }

        protected void btnApplyListSettings_OnClick(object sender, EventArgs e)
        {
            if (cbxEnableViewForItems.Checked)
            {
                var selectedPermissions =
                    (from ListItem item in lbPermissions.Items where item.Selected select item).Select(x => x.Value)
                        .ToList();
                if (!selectedPermissions.Any())
                {
                    cbxEnableViewForItems.Checked = false;
                    return;
                }

                SetEnableForListItems(cbxEnableViewForItems.Checked, selectedPermissions);
            }
            else
            {
                SetEnableForListItems(cbxEnableViewForItems.Checked, null);
            }
            BindPBInfo();
        }

        #region private
        private void Preparation()
        {
            PageTitleSufix = GetTitleSufix(_pbItemType);
            if(!cbxEnableViewForItems.Checked)
                lbPermissions.ClearSelection();

            if (IsPostBack) return;

            string linkTitle;
            btnReturn.PostBackUrl = GetBackLink(_listId, _itemId, out linkTitle);
            btnReturn.Text = linkTitle;

            listPBConfig.Visible = DisplayListPbConfiguration(_pbItemType);
            if (!string.IsNullOrEmpty(_listId))
                cbxEnableViewForItems.Checked = GetEnableForListItems(_listId);

            var currentPerm = GetPermissionsForListItems(_listId);
            foreach (SPRoleDefinition role in SPContext.Current.Web.RoleDefinitions)
            {
                ListItem li = new ListItem();
                li.Text = role.Name;
                li.Value = role.Name;
                li.Selected = currentPerm != null && currentPerm.Contains(role.Name);
                lbPermissions.Items.Add(li);
            }
        }


        private void BindPBInfo()
        {
            var propertiesDatasource = GetObjectProperiesBagByType(_pbItemType, _listId, _itemId);

            if (propertiesDatasource == null || propertiesDatasource.Count <= 0)
            {
                ShowMessage("No properties");
                return;
            }
            gvPropertyBagDatails.DataSource = PrepareDataSource(propertiesDatasource);
            gvPropertyBagDatails.DataBind();
        }

        private PropertyBagItemType GetPbItemType(string listId, string itemId)
        {
            if (!string.IsNullOrEmpty(listId) && !string.IsNullOrEmpty(itemId))
            {
                return PropertyBagItemType.Item;
            }
            if (!string.IsNullOrEmpty(listId) && string.IsNullOrEmpty(itemId))
            {
                return PropertyBagItemType.List;
            }
            return PropertyBagItemType.Web;
        }

        private string GetTitleSufix(PropertyBagItemType type)
        {
            string result;
            switch (type)
            {
                case PropertyBagItemType.Item:
                    result = "List: " + GetListTitle(new Guid(_listId)) + " > Item ID: " + _itemId;
                    break;
                case PropertyBagItemType.List:
                    result = "List: " + GetListTitle(new Guid(_listId));
                    break;
                default:
                    result = "Site: " + SPContext.Current.Web.Title;
                    break;
            }
            return result;
        }

        private string GetListTitle(Guid listId)
        {
            try
            {
                return SPContext.Current.Web.Lists.GetList(listId, false).Title;
            }
            catch (Exception ex)
            {
                ShowMessage(ex.ToString());
            }
            return string.Empty;
        }

        private Hashtable GetObjectProperiesBagByType(PropertyBagItemType propertyBagItemType, string listId, string itemId)
        {
            switch (propertyBagItemType)
            {
                case PropertyBagItemType.Web:
                    return PropertyBagHelper.GetPropertiesForWeb(SPContext.Current.Web);
                case PropertyBagItemType.List:
                    return PropertyBagHelper.GetPropertiesForList(SPContext.Current.Web, new Guid(listId));
                case PropertyBagItemType.Item:
                    return PropertyBagHelper.GetPropertiesForItem(SPContext.Current.Web,
                                                new Guid(listId),
                                                Convert.ToInt32(itemId));
                default: return null;
            }
        }

        private string GetParamFromUrlByName(string paramName)
        {
            return Page.Request.QueryString[paramName] ?? string.Empty;
        }

        private object PrepareDataSource(Hashtable hashtable)
        {
            return hashtable.Cast<DictionaryEntry>().Select(x => new { key = x.Key.ToString(), value = x.Value.ToString() }).ToList();
        }

        private string GetBackLink(string listId, string itemId, out string linkTitle)
        {
            if (!string.IsNullOrEmpty(itemId))
            {
                linkTitle = "Close";
                return "javascript:window.close();";
            }
            if (!string.IsNullOrEmpty(listId))
            {
                linkTitle = "Go to list settings";
                return SPUrlUtility.CombineUrl(SPContext.Current.Web.Url, "/_layouts/15/listedit.aspx?List=" + listId);
            }
            linkTitle = "Go to site settings";
            return SPUrlUtility.CombineUrl(SPContext.Current.Web.Url, "/_layouts/15/settings.aspx");
        }

        private void ShowMessage(string errorMessage)
        {
            MainInfo.Visible = false;
            ErrorMessage.Visible = true;
            ErrorMessageText.Text = errorMessage;
        }

        private bool DisplayListPbConfiguration(PropertyBagItemType type)
        {
            return type == PropertyBagItemType.List;
        }

        private bool GetEnableForListItems(string listId)
        {
            if (string.IsNullOrEmpty(listId)) return false;
            bool result = false;
            var web = SPContext.Current.Web;
            try
            {
                SPList list = web.Lists.GetList(new Guid(listId), true);
                var val = list.GetPropertyValue(EnalblePbvForItemsKey);
                result = !string.IsNullOrEmpty(val) && val != false.ToString();
            }
            catch (Exception ex)
            {
                ShowMessage(ex.ToString());
            }
            return result;
        }

        private List<string> GetPermissionsForListItems(string listId)
        {
            if (string.IsNullOrEmpty(listId)) return null;
            var result = new List<string>();
            var web = SPContext.Current.Web;
            try
            {
                SPList list = web.Lists.GetList(new Guid(listId), true);
                var val = list.GetPropertyValue(EnalblePbvForItemsPermissionsKey);
                if (string.IsNullOrEmpty(val)) return null;
                
                var p = val.Split(new []{','}, StringSplitOptions.RemoveEmptyEntries);
                result.AddRange(p);
            }
            catch (Exception ex)
            {
                ShowMessage(ex.ToString());
            }
            return result;
        }

        private void SetEnableForListItems(bool enable, List<string> permissions)
        {
            if (string.IsNullOrEmpty(_listId)) return;
            var web = SPContext.Current.Web;
            try
            {
                SPList list = web.Lists.GetList(new Guid(_listId), true);
                if (enable)
                {
                    list.DeleteEcbCustomAction(MenuTitle);
                    var permiss = GetResultSPBasePermissions(permissions);
                    list.AddEcbCutomAction(MenuTitle, UrlToViewPage, permiss);
                }
                else
                {
                    list.DeleteEcbCustomAction(MenuTitle);
                }
                list.SetPropertyValue(EnalblePbvForItemsKey, enable.ToString());
                list.SetPropertyValue(EnalblePbvForItemsPermissionsKey, enable ? string.Join(",", permissions): "");
            }
            catch (Exception ex)
            {
                ShowMessage(ex.ToString());
            }
        }

        private SPBasePermissions GetResultSPBasePermissions(List<string> roleNames)
        {
            SPBasePermissions result;
            var roles = new List<SPRoleDefinition>();
            var query = (from SPRoleDefinition roleDef in SPContext.Current.Web.RoleDefinitions select roleDef).ToList();
            foreach (var roleName in roleNames)
            {
                roles.Add(query.First(x => x.Name == roleName));
            }
            result = roles[0].BasePermissions;
            for (int i = 1; i < roles.Count; i++)
                result |= roles[i].BasePermissions;

            return result;
        }
        #endregion
    }
}
